package handler

import (
	"context"
	"errors"
	"go-likaladi-shop/common/base_global"
	"go-likaladi-shop/common/base_util"
	"go.uber.org/zap"
	"google.golang.org/protobuf/types/known/emptypb"
	"gorm.io/gorm"
	"lw-shop/user_service/global/util"
	"lw-shop/user_service/model"
	"lw-shop/user_service/proto"
	"time"
)

type UserServer struct {
}

// GetUserList 获取用户列表
func (us *UserServer) GetUserList(ctx context.Context, req *proto.PageInfo) (*proto.UserListResponse, error) {
	db := base_global.DB
	// 定义一个切片用于接收查询的用户数据
	var users []model.User

	// 使用 GORM 查询所有用户数据，结果存储在 users 切片中
	result := db.Find(&users)

	// 如果查询发生错误，返回错误
	if result.Error != nil {
		zap.S().Errorw("handler=>GetUserList", "错误消息", result.Error)
		return nil, result.Error
	}

	// 构造响应对象
	rsp := &proto.UserListResponse{}

	// 设置返回的总记录数
	rsp.Total = int32(result.RowsAffected)

	// 使用 Scopes 和分页函数设置分页，限制返回的结果数量
	db.Scopes(base_util.Paginate(int(req.Pn), int(req.PSize))).Find(&users)

	// 将查询结果转换为响应对象并添加到 rsp.Data 切片中
	for _, user := range users {
		// 将 model.User 转换为 proto.UserInfoResponse
		userInfoResp := ModelToResponse(user)
		rsp.Data = append(rsp.Data, &userInfoResp)
	}

	// 返回构造的响应对象
	return rsp, nil
}

// GetUserById 通过用户 ID 获取用户信息
func (us *UserServer) GetUserById(ctx context.Context, req *proto.IdRequest) (*proto.UserInfoResponse, error) {
	return querySignUser(func() (*gorm.DB, model.User) {
		var user model.User
		result := base_global.DB.First(&user, req.Id)
		return result, user
	})
}

// GetUserByMobile 通过手机号获取用户信息
func (us *UserServer) GetUserByMobile(ctx context.Context, req *proto.MobileRequest) (*proto.UserInfoResponse, error) {
	return querySignUser(func() (*gorm.DB, model.User) {
		var user model.User
		//通过手机号查询用户 select * from user where mobile = ? limit 1
		result := base_global.DB.Where(&model.User{Mobile: req.Mobile}).First(&user)
		return result, user
	})
}

// 创建新用户
func (us *UserServer) CreateUser(ctx context.Context, req *proto.CreateUserInfo) (*proto.UserInfoResponse, error) {
	var user model.User
	//通过手机号查询用户 select * from user where mobile = ? limit 1
	result := base_global.DB.Where(&model.User{Mobile: req.Mobile}).First(&user)
	// 处理查询过程中的其他错误（例如数据库连接异常）
	if result.Error != nil {
		// 没有找到用户记录, 不代表錯誤=>在錯誤信息中，如果不是找不到用戶記錄的錯誤, 才是真正出錯
		if !errors.Is(result.Error, gorm.ErrRecordNotFound) {
			return nil, base_util.GrpcError(result.Error)
		}
	}

	if result.RowsAffected == 1 {
		return nil, base_util.LogicError("用户已存在")
	}

	user.NickName = req.NickName
	user.Mobile = req.Mobile
	user.Password = util.EncodePassword(req.Password)

	result = base_global.DB.Create(&user)
	if result.Error != nil {
		//return nil, status.Errorf(codes.Internal, result.Error.Error())
		return nil, base_util.GrpcError(result.Error)
	}

	userInfoResp := ModelToResponse(user)
	return &userInfoResp, nil
}

// 更新用户信息
func (us *UserServer) UpdateUser(ctx context.Context, req *proto.UpdateUserInfo) (*emptypb.Empty, error) {
	db := base_global.DB
	//个人中心更新用户
	var user model.User
	result := db.First(&user, req.Id)
	if result.Error != nil {
		return nil, base_util.GrpcError(result.Error)
	}
	if result.RowsAffected == 0 {
		return nil, base_util.LogicError("用户不存在")
	}

	birthDay := time.Unix(int64(req.Birthday), 0)
	user.NickName = req.NickName
	user.Gender = req.Gender
	user.Birthday = &birthDay

	result = db.Save(&user)
	if result.Error != nil {
		return nil, base_util.GrpcError(result.Error)
	}
	return &emptypb.Empty{}, nil
}

// querySignUser 用于查询用户信息，并返回 gRPC 响应格式的用户信息
// 参数:
//   - dbFunc: 一个函数类型参数，该函数返回 (*gorm.DB, model.User)
//     *gorm.DB 用于获取数据库查询结果
//     model.User 是数据库查询得到的用户信息结构体
//
// 返回值:
//   - *proto.UserInfoResponse: gRPC 结构体格式的用户信息响应
//   - error: 可能发生的错误
func querySignUser(dbFunc func() (*gorm.DB, model.User)) (*proto.UserInfoResponse, error) {
	// 调用 dbFunc 执行数据库查询，并获取查询结果
	result, user := dbFunc()

	// 判断查询结果是否为空（即用户不存在）
	if errors.Is(result.Error, gorm.ErrRecordNotFound) {
		// 如果用户不存在，返回自定义错误码，并提示 "用户不存在"
		return nil, base_util.LogicError("用户不存在")
	}

	// 处理查询过程中的其他错误（例如数据库连接异常）
	if result.Error != nil {
		zap.S().Errorw("handler=>querySignUser", "错误消息", result.Error)
		return nil, base_util.GrpcError(result.Error)
	}

	// 将数据库中的用户信息转换为 gRPC 响应格式
	userInfoResp := ModelToResponse(user)

	// 返回用户信息
	return &userInfoResp, nil
}

// 校验用户输入的密码是否正确
func (us *UserServer) CheckPassword(ctx context.Context, req *proto.PasswordCheckInfo) (*proto.CheckResponse, error) {
	return &proto.CheckResponse{
		Success: util.CheckPassword(req.Password, req.EncryptedPassword),
	}, nil
}

// ModelToResponse 将 model.User 转换为 proto.UserInfoResponse
func ModelToResponse(user model.User) proto.UserInfoResponse {
	// 创建一个新的 proto.UserInfoResponse 对象
	userInfoResp := proto.UserInfoResponse{
		Id:       user.ID,
		Password: user.Password,
		NickName: user.NickName,
		Gender:   user.Gender,
		Role:     int32(user.Role),
		Email:    user.Email,
	}

	// 如果生日字段不为 nil，将生日转为 Unix 时间戳
	if user.Birthday != nil {
		userInfoResp.Birthday = uint64(user.Birthday.Unix())
	}

	// 返回转换后的响应对象
	return userInfoResp
}
